// ListCtrlEx.cpp : implementation file
//

#include "stdafx.h"
#include "ApacheLogAnalyzer.h"
#include "ListCtrlEx.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

typedef map<int,int>::value_type value_type;
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx

CListCtrlEx::CListCtrlEx()
{
	m_nSortCol = FALSE;
	m_nSortCol = -1;
}

CListCtrlEx::~CListCtrlEx()
{
}


BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
	//{{AFX_MSG_MAP(CListCtrlEx)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx message handlers

int CListCtrlEx::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat, UINT nMask, int nWidth, int nSubItem)
{
	LVCOLUMN column;
	column.mask = LVCF_TEXT|LVCF_FMT;
	column.pszText = (LPTSTR)lpszColumnHeading;
	column.fmt = nFormat;
	if (nWidth != -1)
	{
		column.mask |= LVCF_WIDTH;
		column.cx = nWidth;
	}
	if (nSubItem != -1)
	{
		column.mask |= LVCF_SUBITEM;
		column.iSubItem = nSubItem;
	}

	m_ColType.insert(value_type(nCol,nMask));

	return CListCtrl::InsertColumn(nCol, &column);
}

void CListCtrlEx::OnColumnClick(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

	if(pNMListView->iSubItem != m_nSortCol){
		m_bAscending = FALSE;
		m_nSortCol = pNMListView->iSubItem;
	}
	else
		m_bAscending = !m_bAscending;

	SortInColumn(pNMListView->iSubItem, m_bAscending);

	*pResult = 0;
}


int CListCtrlEx::SortInColumn(int nCol, BOOL bAscending, int low, int high)
{
	if( nCol >= ((CHeaderCtrl*)GetDlgItem(0))->GetItemCount() )
		return FALSE;

	int colType = m_ColType[nCol];

	if( high == -1 ) high = GetItemCount() - 1;
	int lo = low;
	int hi = high;
	
	CString sMidItem;
	
	if( hi <= lo ) return FALSE;
	sMidItem = GetItemText((lo+hi)/2, nCol);
	
	// loop through the list until indices cross
	while( lo <= hi )
	{
		// rowText will hold all column text for one row
		CStringArray rowText;
		
		// find the first element that is greater than or equal to 
		// the partition element starting from the left Index.
		if( bAscending )
			while( ( lo < high ) && (Compare(GetItemText(lo, nCol),sMidItem,colType)<0))
				++lo;           
		else
			while( ( lo < high ) && (Compare(GetItemText(lo, nCol),sMidItem,colType)>0))
				++lo;
		// find an element that is smaller than or equal to 
		// the partition element starting from the right Index.
		if( bAscending )
			while( ( hi > low ) && (Compare(GetItemText(hi, nCol),sMidItem,colType)>0))
				--hi;           
		else
			while( ( hi > low ) && (Compare(GetItemText(hi, nCol),sMidItem,colType)<0))
				--hi;
		// if the indexes have not crossed, swap                
		// and if the items are not equal
		if( lo <= hi )
		{
			// swap only if the items are not equal
			if(GetItemText(lo, nCol).Compare(GetItemText(hi, nCol))!=0)
			{                               
				// swap the rows
				LV_ITEM lvitemlo, lvitemhi;
                
				int nColCount =	((CHeaderCtrl*)GetDlgItem(0))->GetItemCount();
				rowText.SetSize( nColCount );
                
				int i;
				for( i=0; i < nColCount; i++)
					rowText[i] = GetItemText(lo, i);
                
				lvitemlo.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
				lvitemlo.iItem = lo;
				lvitemlo.iSubItem = 0;
				lvitemlo.stateMask = LVIS_CUT | LVIS_DROPHILITED |
									 LVIS_FOCUSED |  LVIS_SELECTED |
									 LVIS_OVERLAYMASK | LVIS_STATEIMAGEMASK;
				lvitemhi = lvitemlo;
				lvitemhi.iItem = hi;
                
				GetItem( &lvitemlo );
				GetItem( &lvitemhi );
                
				for( i=0; i< nColCount; i++)
					SetItemText(lo, i, GetItemText(hi, i) );
                
				lvitemhi.iItem = lo;
				SetItem( &lvitemhi );
                
				for( i=0; i< nColCount; i++)
					SetItemText(hi, i, rowText[i]);
                
				lvitemlo.iItem = hi;
				SetItem( &lvitemlo );
			}
			
			++lo;
			--hi;
		}
	}
	
	// If the right index has not reached the left side of array
	// must now sort the left partition.
	if( low < hi )
		SortInColumn( nCol, bAscending , low, hi);
	
	// If the left index has not reached the right side of array
	// must now sort the right partition.
	if( lo < high )
		SortInColumn( nCol, bAscending , lo, high );
	
	return TRUE;
}

int CListCtrlEx::Compare(LPCTSTR str1, LPCTSTR str2, UINT colType)
{
	if(colType == LCMASK_STRING){
		CString cstr1(str1);
		return cstr1.Compare(str2);
	}
	if(colType == LCMASK_INTEGER){
		return atoi(str1) - atoi(str2);
	}
	if(colType == LCMASK_FLOAT){
		return (atof(str1) > atof(str2))?1:0;
	}
	if(colType == LCMASK_PERCENT){
		float f1,f2;
		sscanf(str1,"%f%%",&f1);
		sscanf(str2,"%f%%",&f2);
		int i1 = f1 * 100;
		int i2 = f2 * 100;
		return i1 - i2;
	}
	return 0;
}
